package com.chezai.client.server;

import com.orhanobut.logger.Logger;

import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

/**
 * tcp客户端
 *
 * @author shenliuyang
 *         <p/>
 *         2016年8月16日上午10:14:05
 */
public abstract class NettySocketClient {


    protected String serverAddress;// 服务端地址
    protected int serverPort;// 服务端口
    protected Channel channel;// 与服务端的通道
    protected AtomicBoolean status = new AtomicBoolean();
    protected EventLoopGroup workerGroup = new NioEventLoopGroup();

    public NettySocketClient(String serverAddress, int serverPort) {
        super();
        this.serverAddress = serverAddress;
        this.serverPort = serverPort;
    }

    public NettySocketClient() {
        super();
    }

    /**
     * 连接服务端
     */
    public void connect() {
        if (!status.compareAndSet(false, true)) {
            return;
        }
        new Thread(){
            @Override
            public void run() {
                try {
                    Logger.t("connect").i("正在连接服务器。。。");
                    Bootstrap b = new Bootstrap();
                    b.group(workerGroup);
                    b.channel(NioSocketChannel.class);
                    b.option(ChannelOption.SO_KEEPALIVE, true);
                    b.handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            for (ChannelHandler c : channelHandlerList()) {
                                ch.pipeline().addLast(c);
                            }
                        }
                    });
                    ChannelFuture f = b.connect(serverAddress, serverPort).sync();
                    Logger.t("connect").i( "serverAddress。。。" + serverAddress + "--" +serverPort);
                    channel = f.channel();
                    channel.closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
                        @Override
                        public void operationComplete(Future<? super Void> future) throws Exception {
                            close();
                        }
                    });
                    if (isConnect()){
                        Logger.t("connect").i("connect", "tcp链接成功");
                    }
                } catch (Throwable t) {
                    status.set(false);
                    Logger.t("connect").e("connect to server error ", t);
                }
            }
        }.start();

    }

    public void close() {
        try {
            if (!status.compareAndSet(true, false)) {
                return;
            }
            channel.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean isConnect() {
        return status.get();
    }

    /**
     * 子类提供通道处理器
     */
    protected abstract List<? extends ChannelHandler> channelHandlerList();

    protected void setServerAddress(String address) {
        this.serverAddress = address;
    }

    protected void setServerPort(int port) {
        this.serverPort = port;
    }
}
